/*
 *      IL_SSA_Depot.java
 *
 *      Copyright 2008 Pablo Nicolas Diaz Bilotto <pablonicolas.diaz@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

package ilanguage;

import ilanguage.iltokens.IL_BaseSSA;
import ilanguage.iltokens.IL_SSA;
import ilanguage.iltokens.SequenciableSSA;
import ilanguage.iltokens.operations.control.Branch;
import ilanguage.iltokens.operations.control.BranchByFalse;

import java.util.Stack;
import java.util.Vector;

import lexer.EntryType;
import symbolStorageService.ISymEntry;
import symbolStorageService.ISymTable;
import errorService.IErrorReporter;


/**
 * esta clase sirve para poner los tercetos a medida que se van generando
 * esta es usada por el parser como deposito de los tercetos para cuando el
 * parser los reconoce, esta clase los tome :)
 *  *
 * The Class IL_SSA_Depot.
 */
public class IL_SSA_Depot extends Vector<IL_SSA> {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = -8404506372807264775L;

	/** The mysym table. */
	private ISymTable mysymTable;

	/** The myreporter. */
	private IErrorReporter myreporter;

	/** The my jmp stack. */
	private Stack<IL_SSA> myJmpStack;

	/** The my var stack. */
	private Stack<IL_SSA> myVarStack;

	/** The deffered token. */
	private Stack<IL_SSA> defferedToken;

	/** The hasoneerrortoken. */
	private boolean hasoneerrortoken = false;

	/** The token do. */
	private boolean tokenDo = false;

	/**
	 * Instantiates a new i l_ ss a_ depot.
	 *
	 * @param symTable the sym table
	 * @param reporter the reporter
	 */
	public IL_SSA_Depot(final ISymTable symTable, final IErrorReporter reporter) {
		super();
		this.mysymTable = symTable;
		this.myreporter = reporter;
		this.myJmpStack = new Stack<IL_SSA>();
		this.myVarStack = new Stack<IL_SSA>();
		this.defferedToken = new Stack<IL_SSA>();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ilanguage.ILStreamer#appendToken(ilanguage.ILToken)
	 */
   /**
	 * Aca pongo un token al final de mi mismo.
	 * tambien resuelvo referencias
	 *
	 * @param t the t
	 *
	 * @return the i l_ ssa
	 */
	public final IL_SSA appendToken(final IL_SSA t) {
		if (!t.isDiscartable()) {
			if (this.tokenDo) {
				this.myJmpStack.add(t);
				tokenDo = false;
			}
			this.add(t);
			while (!defferedToken.isEmpty()) {
				defferedToken.pop().setReference(t);
				t.setRefPrint(true);
			}
        } else {
			this.setHasoneerrortoken(true);
		}
		return t;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#CheckVarStack(ILanguage.IL_Token, int)
	 */
	/**
	 * Check var stack.
	 * Este asigna tipos a una lista de variables y detecta las redeclaraciones
	 * @param tkn the tkn
	 * @param line the line
	 *
	 * @return true, if successful
	 */
	public boolean checkVarStack(final IL_SSA tkn, final int line) {
		boolean goodStack = true;
		ISymEntry s1 = this.mysymTable.get(tkn.getValue());
		while (!myVarStack.empty()) {
			IL_BaseSSA token = myVarStack.pop();
			ISymEntry entry = this.mysymTable.get(token.getValue());
			if (entry == null || s1 == null) {
				myreporter.reportError(line, "Que Hiciste con la SymTable?");
				this.myVarStack.clear();
				return false;
			} else {
				if (!entry.isTyped() && entry.getType() != EntryType.STRING) {
					entry.setType(s1.getType());
				} else {
					myreporter.reportError(line, "GCI : La Variable "
							+ token.getValue() + " esta declarada con el tipo "
							+ entry.getType()
							+ " y se intenta redeclarar con el tipo "
							+ tkn.getValue());
					goodStack = false;
				}
			}
		}
		return goodStack;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.util.Vector#clear()
	 */
	@Override
	public void clear() {
		SequenciableSSA.resetSequence();
		super.clear();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#ClearVarStack()
	 */
	/**
	 * Limpia la pila de Variables (en caso de errores)
	 * Clear var stack.
	 */
	public void clearVarStack() {
		this.myVarStack.clear();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#GenerateUntil(ILanguage.IL_Token)
	 */
	/**
	 * Genero el codigo del until
	 *
	 * @param cond the cond
	 *
	 * @return the i l_ ssa
	 */
	public IL_SSA generateUntil(final IL_SSA cond) {
		IL_SSA X=this.myJmpStack.pop();
		X.setRefPrint(true);
		return this.appendToken(new BranchByFalse(X, cond));
	}

	/**
	 * Gets the jmp stack.
	 *
	 * @return the jmp stack
	 */
	public final Stack<IL_SSA> getJmpStack() {
		return myJmpStack;
	}

	/**
	 * Gets the var stack.
	 *
	 * @return the var stack
	 */
	public final Stack<IL_SSA> getVarStack() {
		return myVarStack;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ilanguage.ILStreamer#hasErrors()
	 */
	/**
	 * Checks for errors., si los hubo es la forma de saberlo
	 * mas adelante ;)
	 *
	 * @return true, if successful
	 */
	public boolean hasErrors() {
		return this.isHasoneerrortoken();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#JmpStackElseize(int)
	 */
	/**
	 * Jmp stack elseize.
	 * hacer el "else" del if
	 * mete un salto incondicional incompleto
	 *
	 * @param line the line
	 */
	public void jmpStackElseize(final int line) {
		IL_SSA BFTmp = this.myJmpStack.pop();
		IL_SSA tkn;
		tkn = appendToken(new Branch(null));
		myJmpStack.push(tkn);
		setDefferedToken(BFTmp);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#JmpStackPush(ILanguage.IL_Token, int)
	 */

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#JmpStackPop(ILanguage.IL_Token)
	 */
	/**
	 * hago un pop y meto el SSA para poder resolver su salto
	 * Jmp stack pop.
	 */
	public IL_SSA jmpStackPop() {
		return setDefferedToken(this.myJmpStack.pop());
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#JmpStackPopDiscard()
	 */
	/**
	 * descarto el tope de Jmp stack (errores)
	 */
	public void jmpStackPopDiscard() {
		this.myJmpStack.pop();
		this.setHasoneerrortoken(true);
	}

	/**
	 * meto un Branch por falso incompleto en la pila
	 *
	 * @param tkn the tkn
	 * @param line the line
	 */
	public void jmpStackPush(final IL_SSA tkn, final int line) {
		// branch cuando es 0, o sea falso
		// meto el token de evaluacion en la
		// pila para resolverlo despues!
		myJmpStack.push(this.appendToken(new BranchByFalse(null, tkn)));
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#LabelizeDo()
	 */
	/**
	 * indico q quiero hacer un "DO"
	 * Labelize do.
	 */
	public void labelizeDo() {
		this.tokenDo = true;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see ILanguage.IL_Streamer#PushVarStack(ILanguage.IL_Token)
	 */
	/**
	 * Poner SSA'S en la pila de variables (para resolver el tipo)
	 *
	 * @param tkn the tkn
	 */
	public final void pushVarStack(final IL_SSA tkn) {
		this.myVarStack.push(tkn);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.util.Vector#removeAllElements()
	 */
	@Override
	public synchronized void removeAllElements() {
		super.removeAllElements();
		this.setHasoneerrortoken(false);
	}

	/**
	 * Meto en la pila de diferidos a el parametro
	 *
	 * @param defferedToken the new deffered token
	 */
	private IL_SSA setDefferedToken(IL_SSA defferedToken) {
		this.defferedToken.add(defferedToken);
		return defferedToken;
	}

	/**
	 * Sets the jmp stack.
	 *
	 * @param jmpStack the new jmp stack
	 */
	public final void setJmpStack(Stack<IL_SSA> jmpStack) {
		myJmpStack = jmpStack;
	}

	/**
	 * Sets the var stack.
	 *
	 * @param varStack the new var stack
	 */
	public final void setVarStack(final Stack<IL_SSA> varStack) {
		myVarStack = varStack;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.util.AbstractCollection#toString()
	 */
	@Override
	public String toString() {
		StringBuffer s = new StringBuffer();
		for (IL_BaseSSA t : this) {
			s.append(t.toString() + '\n');
		}
		return s.toString();
	}

	public void setHasoneerrortoken(boolean hasoneerrortoken) {
		this.hasoneerrortoken = hasoneerrortoken;
	}

	public boolean isHasoneerrortoken() {
		return hasoneerrortoken;
	}


}
